
#ifndef GLIST_H
#define GLIST_H

template <class T> class GList {
public:
	GList() {
		sizeofdata = 0;
		sizeofarray = 10;
		array = new T[10];
	}
	
	GList(const GList<T>& list) {
		sizeofdata = list.sizeofdata;
		sizeofarray = list.sizeofarray;
		array = new T[sizeofarray];
		for(int i=0; i<sizeofdata; i++) {
			array[i] = list.array[i];
		}
	}
	
	~GList() {
		delete[] array;
		array = 0;
	}
	
	void clear() {
		delete[] array;
		array = new T[sizeofarray];
		sizeofdata = 0;
	}
	
	int size() const {
		return sizeofdata;
	}
	
	void push_back(const T& in) {
		checkResize();
		array[sizeofdata] = in;
		sizeofdata++;
	}
	
	T pop_back() {
		sizeofdata--;
		T tmp = array[sizeofdata];
		array[sizeofdata].~T();
		return tmp;
	}
	
	T pop_front() {
		T tmp = array[0];
		shiftLeftOne(1, sizeofdata);
		array[sizeofdata-1].~T();
		sizeofdata--;
		return tmp;
	}
	
	int indexOf(const T& in, int start = 0) const {
		for(int i=start; i<sizeofdata; i++) {
			if(array[i] == in) return i;
		}
		return -1;
	}
	
	void removeOne(const T& in) {
		for(int i=0; i<sizeofdata; i++) {
			if(array[i] == in) {
				shiftLeftOne(i+1, sizeofdata-1);
				sizeofdata--;
				return;
			}
		}
		
	}
	
	void removeAll(const T& in) {
		for(int i=sizeofdata-1; i>=0; i--) {
			if(array[i] == in) {
				array[i].~T();
				shiftLeftOne(i+1, sizeofdata-1);
				sizeofdata--;
			}
		}
	}
	
	void removeAt(const int i) {
		array[i].~T();
		shiftLeftOne(i+1, sizeofdata-1);
		sizeofdata--;
	}
	
	T& at(int i) const {
		return array[i];
	}
	
	inline T& operator[](int i) const {
		return at(i);
	}
	
	const T* data() const {
		return array;
	}
	
	GList<T>& operator+(GList<T>& list) {
		int length = list.size();
		for(int i=0; i<length; i++) {
			this->push_back(list[i]);
		}
		return *this;
	}
	
	
	//**********
	//iterator interface
	//**********
	T* begin() {
		return array;
	}
	
	T* end() {
		return array + sizeofdata*sizeof(T);
	}
	
	class iterator {
	public:
		iterator(T* start = 0) {
			ptr = start;
			increment = sizeof(T);
		}
		
		bool operator<(const T* cmp) const { return cmp < ptr; }
		
		void operator=(const T* start) { ptr = start; }
		
		void operator++(int in) { ptr += increment; }
		void operator--(int in) { ptr -= increment; }
		
		T& operator*() { *ptr; }
		
		
	private:
		T* ptr;
		int increment;
	};
	
protected:
	inline void shiftLeftOne(int a, int b) {
		for(int k=a; k<=b; k++) {
			array[k-1] = array[k];
		}
	}
	
	
	inline void checkResize() {
		if((1+sizeofdata) > sizeofarray) {
			int mult = 2;
			while((1+sizeofdata) > (sizeofarray * mult)) {
				mult *= 2;
			}
			int sizeofnewarray = sizeofarray * mult * sizeof(T);
			T* tmparray = new T[sizeofnewarray];
			for(int i=0; i<sizeofarray; i++) tmparray[i] = array[i];
			delete[] array;
			sizeofarray = sizeofnewarray;
			array = tmparray;
			tmparray = 0;
		}
	}
	
private:
	T* array;
	int sizeofdata;
	int sizeofarray;
	
};


#endif // GLIST_H
